//
//  File.swift
//  
//
//  Created by Ink on 2024/2/15.
//

import Foundation

public typealias EventHandler = (_ data: Any?) -> Void

/// handler type
public protocol HandlerEventType: Hashable {}

private class HanldlerPayload {
    
    let handler: EventHandler
    
    init(_ kHandler: @escaping EventHandler) {
        
        handler = kHandler
    }
}

public class HandlerEventBus<T: HandlerEventType> {
            
    private var dataStore = [T : NSMapTable<AnyObject, HanldlerPayload>]()
    
    public init() {}
}

// MARK: trigger
public extension HandlerEventBus {
    
    /// trigger handler
    /// - Parameters:
    ///   - type: kindof HandlerEventType
    ///   - obj: The handler belong to object
    ///   - data: The handler can to trigger with data
    @discardableResult
    func trigger(type: T, obj: AnyObject? = nil, data: Any? = nil) -> Self {
        
        if let obj = obj {
            
            dataStore[type]?.object(forKey: obj)?.handler(data)
        }
        else {
            
            let value_enumeration = dataStore[type]?.objectEnumerator()
            
            while let value = value_enumeration?.nextObject() as? HanldlerPayload {
                
                value.handler(data)
            }
        }
        
        return self
    }
}

// MARK: register
public extension HandlerEventBus {
    
    /// register Handler
    /// - Parameters:
    ///   - type: kindof HandlerEventType
    ///   - obj: The handler belong to object
    ///   - handler: The handler can to trigger
    @discardableResult
    func register(type: T, obj: AnyObject, handler: @escaping EventHandler) -> Self {
        
        if dataStore[type] == nil {
            
            dataStore[type] = NSMapTable<AnyObject, HanldlerPayload>.weakToStrongObjects()
        }
        
        dataStore[type]?.setObject(HanldlerPayload(handler), forKey: obj)
        
        return self
    }
}

// MARK: unregister
public extension HandlerEventBus {
    
    /// unregister Handler
    ///
    /// - Parameters:
    ///   - type: kindof HandlerEventType
    ///   - obj: The handler belong to object
    @discardableResult
    func unregister(type: T? = nil, obj: AnyObject? = nil ) -> Self {
          
        if let obj = obj {
            
            if let type = type {
                
                dataStore[type]?.removeObject(forKey: obj)
            }
            else {
                
                dataStore.forEach { $0.value.removeObject(forKey: obj)}
            }
        }
        else if let type = type {
            
            dataStore.removeValue(forKey: type)
        }
        
        return self
    }
}


